// 构造函数 (Constructor): 负责对象的初始化，在对象创建时自动调用。
// 析构函数 (Destructor): 负责对象的资源清理，在对象销毁时自动调用。
// 拷贝构造 vs 拷贝赋值: 前者是从无到有创建一个新对象（初始化），后者是修改一个已存在的对象（赋值）。
// 深拷贝 vs 浅拷贝: 当类管理动态资源（如裸指针、文件句柄）时，必须实现深拷贝（复制资源本身），否则浅拷贝（仅复制指针或句柄）会导致多个对象指向同一资源，引发重复释放等严重错误。
// 移动语义 (Move Semantics): C++11引入的核心特性，通过移动构造和移动赋值，将资源从一个临时或将亡对象“转移”到另一个对象，避免了不必要的深拷贝，极大提升了性能。std::move 是将一个左值“伪装”成右值的工具，以便触发移动操作。
// The Rule of Three/Five (三/五法则):
// 旧版 (Rule of Three): 如果你定义了析构函数、拷贝构造、拷贝赋值中的任意一个，那么你应该把三者都定义出来。
// 新版 (Rule of Five): 在 C++11 中，如果你定义了上述三者或移动构造、移动赋值中的任意一个，那么你应该把这五个都定义出来，以实现完整的资源管理和性能优化。
// explicit: 用在你不希望发生隐式类型转换的单参数构造函数（或多参数但其他有默认值的构造函数）前，增强代码的可读性和类型安全。

#include<iostream>
#include<string>
#include<vector>

//用于演示的“小工具”类
class Gadget{
private:
    int id;
    std::string name;
    int* data;          //用于演示浅拷贝和深拷贝

public:
    //1. 默认无参构造函数 无需参数构造对象
    Gadget() : id(0), name("N/A"), data(new int[5]) {
        std::cout << "  [LOG] Default constructor called for ID: " << id << std::endl;
        for(int i = 0; i < 5; i++) {
            data[i] = 0;
        }
    };

    //2. 带参数的构造函数 初始化时提供具体数据
    //使用explicit关键字可以防止不安全的类型转换
    explicit Gadget(int i, const std::string& n) : id(i), name(n), data(new int[5]) {
        std::cout << "  [LOG] Parameterized constructor called for ID: " << id << std::endl;
        for(int i = 0; i < 5; i++)
            data[i] = id; // 用id填充，方便观察
    }

    //3.委托构造函数(C++11): 一个构造函数可以调用同一个类的另一个构造函数
    // 为了减少代码重复
    explicit Gadget(int i) : Gadget(i, "Default Name") {
        std::cout << "  [LOG] Delegating constructor called, which then called parameterized constructor." << std::endl;
    }

    //4. 拷贝构造函数: 使用已经存在的一个对象来创建一个新对象
    //必须进行深拷贝 否则会导致两个对象共享一块‘data’内存 导致悬挂指针或者重复释放
    Gadget(const Gadget& other) : id(other.id), name(other.name), data(new int[5]) {
        std::cout << "  [LOG] Copy constructor called. Copying from ID: " << other.id << std::endl;
        for(int i = 0; i < 5; i++) {
            this->data[i] = other.data[i];
        }
    }

    //5.移动构造函数(C++11): 直接获取临时对象的右值资源，避免了拷贝
    //参数的右值引用'&&' 并且必须标记为'noexcept'
    Gadget(Gadget&& other) noexcept : id(other.id), name(std::move(other.name)), data(other.data) {
        std::cout << "  [LOG] Move constructor called. Moving from ID: " << other.id << std::endl;
        //将源对象的指针设置为nullptr 防止释放我们移动构造的对象的资源
        other.data = nullptr;
    }

    //----赋值运算符家族------
    //拷贝赋值运算符
    Gadget& operator=(const Gadget& other) {
        std::cout << "  [LOG] Copy assignment operator called. Assigning from ID: " << other.id << std::endl;
        if(this == &other) {        //防止自我赋值
            return *this;
        }
        //释放当前对象资源
        delete[] this->data;
        //重新分配资源进行深拷贝
        this->id = other.id;
        this->name = other.name;
        data = new int[5];
        for(int i = 0; i < 5; i++) {
            this->data[i] = other.data[i];
        }

        return *this;           //返回自身的引用
    }

    //移动赋值运算符
    Gadget& operator=(Gadget&& other) noexcept{
        std::cout << "  [LOG] Move assignment operator called. Moving from ID: " << other.id << std::endl;
        if(this == &other) {    //防止自我复制
            return *this;
        }
        //释放当前对象的资源
        delete[] this->data;
        //窃取源对象的资源
        this->id = other.id;
        this->name = std::move(other.name);
        this->data = other.data;
        //把源对象的置为空
        other.data = nullptr;
        return *this;           //返回自身的引用
    }

    //-----析构函数-----
    ~Gadget() {
        std::cout << "  [LOG] Destructor called for ID: " << id << ". ";
        if(data != nullptr) {
            std::cout << "Releasing memory." << std::endl;
            delete[] data;
            data = nullptr; // 最佳实践：释放后置空
        } else {
            std::cout << "No memory to release." << std::endl;
        }
    };

    //展示数据
    void display() const{
        std::cout << "  > Gadget { ID: " << this->id << ", Name: '" << this->name << "', ";
        if(data) {
            std::cout << "Data: [" << data[0] << ", " << data[1] << ", ...] }" << std::endl;
        } else {
            std::cout << "Data: [nullptr] }" << std::endl;
        }
    }
};

//一个返回gadget对象的工厂函数 用于演示移动构造
Gadget createGadget(int id) {
    std::cout << "  Entering createGadget factory..." << std::endl;
    Gadget g(id, "Temporary Gadget");
    std::cout << "  Leaving createGadget factory..." << std::endl;
    return g; // 返回时，编译器通常会使用NRVO优化，或触发移动构造
}

int main() {
    std::cout << "--- 1. Default constructor ---\n";
    Gadget g1;
    g1.display();

    std::cout << "\n--- 2. Parameterized constructor ---\n";
    Gadget g2(2, "Smart Watch");
    g2.display();

    std::cout << "\n--- 3. Delegating constructor ---\n";
    Gadget g3(3);
    g3.display();

    std::cout << "\n--- 4. Copy constructor ---\n";
    Gadget g4(g2);  
    std::cout << "  Source g2: "; g2.display();
    std::cout << "  Copied g4: "; g4.display();

    std::cout << "\n--- 5. Copy assignment operator ---\n";
    g1 = g3;
    std::cout << "  g1 after being assigned from g3: "; g1.display();

    std::cout << "\n--- 6. Move constructor (from std::move) ---\n";
    Gadget g5(std::move(g4));
    std::cout << "  g5 (moved from g4): ";
    g5.display();
    std::cout << "  g4 (after being moved): ";
    g4.display();

    std::cout << "\n--- 7. Move constructor (from temporary object) ---\n";
    Gadget g6 = createGadget(303);
    std::cout << "  g6 (created from factory's temporary object): ";
    g6.display();

    std::cout << "\n--- 8. Move assignment operator (from temporary object) ---\n";
    g1 = createGadget(404);
    std::cout << "  g1 (after being move-assigned from temporary object): ";
    g1.display();
    
    // Gadget g_test = 505; // 编译错误！因为构造函数是 explicit 的
    // Gadget g_test(505); // 这样才是正确的显式调用

    std::cout << "\n--- End of main. Objects will be destructed in reverse order of creation. ---\n";
    return 0;
}